/*
 * @Description: 右键菜单指令
 * @Author: HuiSir<273250950@qq.com>
 * @Date: 2021-10-26 15:59:44
 * @LastEditTime: 2025-10-15 18:26:10
 */
import { Directive } from "vue";
import DomCreate from "@/utils/DomCreate";
import "./style.scss";

/**
 * 右键菜单自定义按钮
 */
export interface CtxMenuBtn {
  name: string;
  icon?: string;
  disabled?: boolean;
  callback: (el: HTMLElement) => void;
  /**
   * 显隐,默认显示,这里加入函数模式，用于手动加入条件进行控制
   */
  hide?: boolean | ((el: HTMLElement) => boolean);
}

const contextMenu: Directive = {
  created(_, binding) {
    const vm = binding.instance as Record<string, unknown>;
    vm.ctxMenuDom = new DomCreate("div", {}, "fy-ctx-menu");
  },
  beforeMount(el: HTMLElement, binding) {
    const vm = binding.instance as Record<string, unknown>;
    const ctxMenuDom = vm.ctxMenuDom as DomCreate;

    el.oncontextmenu = ({ clientX, clientY }: MouseEvent) => {
      removeCtxMenu(ctxMenuDom);
      initCtxMenu(ctxMenuDom, binding.value, el);
      addListenerOtherClick(ctxMenuDom);
      ctxMenuDom.setAttr("style", `left:${clientX}px;top:${clientY}px`);
      ctxMenuDom.getElement()!.onclick = (ev) => {
        const menuIndex: number = Number(
          (ev.target as HTMLElement).dataset.index!
        );
        const menuItem = (binding.value as CtxMenuBtn[])[menuIndex];
        if (menuItem && !menuItem.disabled) {
          menuItem.callback(el);
          removeCtxMenu(ctxMenuDom);
        }
      };
      return false;
    };
  },
  beforeUnmount(el, binding) {
    el.oncontextmenu = null;
    const vm = binding.instance as Record<string, DomCreate>;
    vm.ctxMenuDom.remove();
  },
};

/**
 * 初始化
 */
function initCtxMenu(
  ctxMenuDom: DomCreate,
  btnOptionsList: CtxMenuBtn[],
  el: HTMLElement
) {
  if (btnOptionsList.length == 0) {
    return;
  }

  let btnHtml = "";

  btnOptionsList.forEach((item, index) => {
    if (
      (typeof item.hide === "function" && item.hide(el)) ||
      item.hide === true
    ) {
      return;
    }

    btnHtml += `<div class="ctx-menu-btn${
      item.disabled ? " disabled" : ""
    }" data-index="${index}">
                ${
                  item.icon
                    ? `<i class="${item.icon} ctx-menu-icon" data-index="${index}"></i>`
                    : ""
                }
                <span class="ctx-menu-span" data-index="${index}">${
      item.name
    }</span>
            </div>`;
  });

  ctxMenuDom.innerHTML(btnHtml);

  // 判断是否已经插入元素
  if (document.body.getElementsByClassName(ctxMenuDom.className).length === 0) {
    document.body.append(ctxMenuDom.getElement()!);
  }
}

/**
 * 监听点击别处关闭菜单
 */
function addListenerOtherClick(ctxMenuDom: DomCreate) {
  if (ctxMenuDom.temp) {
    return;
  }
  const callback = (e: MouseEvent) => {
    const targetClass = (e.target as HTMLElement).className;
    const isCtxMenuDiv =
      typeof targetClass === "string" && targetClass.includes("ctx-menu");
    if (!isCtxMenuDiv) {
      removeCtxMenu(ctxMenuDom);
    } else {
      (e.target as HTMLElement).oncontextmenu = () => false;
    }
  };
  document.addEventListener("click", callback, true);
  document.addEventListener("contextmenu", callback, true);
  ctxMenuDom.temp = callback;
}

/**
 * 取消监听
 */
function removeCtxMenu(ctxMenuDom: DomCreate) {
  ctxMenuDom.remove();
  if (ctxMenuDom.temp) {
    document.removeEventListener("click", ctxMenuDom.temp, true);
    document.removeEventListener("contextmenu", ctxMenuDom.temp, true);
    ctxMenuDom.temp = null;
  }
}

export default contextMenu;
